﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Engine
{
    public class ModelDrawer
    {
        static ContentManager mContent;
        static List<Model> mModels;
        static public Model player;
        static public Model zombie;

        #region Weapons
        public static Model Mp5;
        public static Model pistol;
        public static Model Type95;
        static Model mp5Laser;
        static Model pistolLaser;
        static Model type95Laser;
        static Model bullet;
        #endregion

        static Model floor;
        static public List<Model> mHouse;
        static public List<Model> mStatues;
        
        static public void LoadContent(ContentManager content)
        {
            mContent = content;
            player = content.Load<Model>("models/CubeTest");
            player.Tag = "Player";
            zombie = content.Load<Model>("models/Zombie");
            zombie.Tag = "Zombie1";
            bullet = content.Load<Model>("models/bullet");
            bullet.Tag = "Bullet";
            Mp5 = content.Load<Model>("models/Weapons/Mp5");
            Mp5.Tag = "Mp5";
            pistol = content.Load<Model>("models/Weapons/Pistol");
            pistol.Tag = "pistol";
            Type95 = content.Load<Model>("models/Weapons/Type95");
            Type95.Tag = "Type95";
            type95Laser = content.Load<Model>("models/Weapons/Type95Laser");
            type95Laser.Tag = "type95Laser";
            pistolLaser = content.Load<Model>("models/Weapons/PistolLaser");
            pistolLaser.Tag = "pistolLaser";
            mp5Laser = content.Load<Model>("models/Weapons/Mp5Laser");
            mp5Laser.Tag = "mp5Laser";

            #region House Models
            mHouse = new List<Model>();

            floor = content.Load<Model>("Models/House/Floor1");
            floor.Tag = "Floor";
            mHouse.Add(floor);
            floor = content.Load<Model>("Models/House/Floor2");
            floor.Tag = "Floor";
            mHouse.Add(floor);
            floor = content.Load<Model>("Models/House/Floor3");
            floor.Tag = "Floor";
            mHouse.Add(floor);
            floor = content.Load<Model>("Models/House/Floor4");
            floor.Tag = "Floor";
            mHouse.Add(floor);
            floor = content.Load<Model>("Models/House/Floor5");
            floor.Tag = "Floor";
            mHouse.Add(floor);
            floor = content.Load<Model>("Models/House/Floor6");
            floor.Tag = "Floor";
            mHouse.Add(floor);
            mHouse.Add(content.Load<Model>("Models/House/Wall1"));
            mHouse.Add(content.Load<Model>("Models/House/Wall2"));
            mHouse.Add(content.Load<Model>("Models/House/Wall3"));
            mHouse.Add(content.Load<Model>("Models/House/Wall4"));
            mHouse.Add(content.Load<Model>("Models/House/Wall5"));
            mHouse.Add(content.Load<Model>("Models/House/Wall6"));
            mHouse.Add(content.Load<Model>("Models/House/Wall7"));
            mHouse.Add(content.Load<Model>("Models/House/Wall8"));
            mHouse.Add(content.Load<Model>("Models/House/Wall9"));
            mHouse.Add(content.Load<Model>("Models/House/Wall10"));
            mHouse.Add(content.Load<Model>("Models/House/Wall11"));
            mHouse.Add(content.Load<Model>("Models/House/Wall12"));
            mHouse.Add(content.Load<Model>("Models/House/Wall13"));
            mHouse.Add(content.Load<Model>("Models/House/Wall14"));
            mHouse.Add(content.Load<Model>("Models/House/Wall15"));
            mHouse.Add(content.Load<Model>("Models/House/Wall16"));
            mHouse.Add(content.Load<Model>("Models/House/Wall17"));
            mHouse.Add(content.Load<Model>("Models/House/Wall18"));
            mHouse.Add(content.Load<Model>("Models/House/Wall19"));
            mHouse.Add(content.Load<Model>("Models/House/Wall20"));
            mHouse.Add(content.Load<Model>("Models/House/Wall21"));

            mStatues = new List<Model>();
            mStatues.Add(content.Load<Model>("Models/House/EstatuaSandwitch"));
            mStatues.Add(content.Load<Model>("Models/House/EstatuaMinas"));
            mStatues.Add(content.Load<Model>("Models/House/EstatuaBalas"));
            mStatues.Add(content.Load<Model>("Models/House/Silla1"));
            mStatues.Add(content.Load<Model>("Models/House/Silla2"));
            mStatues.Add(content.Load<Model>("Models/House/Silla3"));
            mStatues.Add(content.Load<Model>("Models/House/Silla4"));
            mStatues.Add(content.Load<Model>("Models/House/Silla5"));
            mStatues.Add(content.Load<Model>("Models/House/Silla6"));
            mStatues.Add(content.Load<Model>("Models/House/Cama1"));
            mStatues.Add(content.Load<Model>("Models/House/Cama2"));
            mStatues.Add(content.Load<Model>("Models/House/MesaDeLuz1"));
            mStatues.Add(content.Load<Model>("Models/House/MesaDeLuz2"));
            mStatues.Add(content.Load<Model>("Models/House/MesaRedonda"));
            mStatues.Add(content.Load<Model>("Models/House/MesaLarga"));
            mStatues.Add(content.Load<Model>("Models/House/Heladera"));
            mStatues.Add(content.Load<Model>("Models/House/Mesada"));
            mStatues.Add(content.Load<Model>("Models/House/Inodoro"));
            mStatues.Add(content.Load<Model>("Models/House/Lavamanos"));
      


            #endregion

            mModels = new List<Model>();
            mModels.Add(player);
            mModels.Add(zombie);
            mModels.Add(bullet);
            mModels.Add(Mp5);
            mModels.Add(pistol);
            mModels.Add(Type95);
            mModels.Add(mp5Laser);
            mModels.Add(pistolLaser);
            mModels.Add(type95Laser);

        }

        #region Collisions
        static public BoundingBox GetBoundingBoxesFromModel(Model model)
        {
            
            Matrix[] modelTransformations = new Matrix[model.Bones.Count];
            BoundingBox boundingBox = new BoundingBox();
            
            model.CopyAbsoluteBoneTransformsTo(modelTransformations);
            for (int meshNumber = 0; meshNumber < model.Meshes.Count; meshNumber++)
            {
                
                ModelMesh mesh = model.Meshes[meshNumber];
                
                VertexPositionNormalTexture[] vertices =
                      new VertexPositionNormalTexture[mesh.VertexBuffer.SizeInBytes / VertexPositionNormalTexture.SizeInBytes];

                mesh.VertexBuffer.GetData<VertexPositionNormalTexture>(vertices);

                Vector3[] vertexs = new Vector3[vertices.Length];

                for (int index = 0; index < vertexs.Length; index++)
                {
                    vertexs[index] = vertices[index].Position;
                }

                //BoundingBox Transforms
                boundingBox = BoundingBox.CreateMerged(boundingBox, BoundingBox.CreateFromPoints(vertexs));
                boundingBox.Min = Vector3.Transform(boundingBox.Min,
                    modelTransformations[model.Meshes[meshNumber].ParentBone.Index] * Matrix.Identity);
                boundingBox.Max = Vector3.Transform(boundingBox.Max,
                    modelTransformations[model.Meshes[meshNumber].ParentBone.Index] * Matrix.Identity);


                boundingBox = fixBoundingBoxData(boundingBox);  
            }

            return boundingBox;
        }

        static private BoundingBox fixBoundingBoxData(BoundingBox AABB)
        {
            Vector3 min = AABB.Min, max = AABB.Max;
            float tempData = 0f;
            if (min.X > max.X) { tempData = min.X; min.X = max.X; max.X = tempData; }
            if (min.Y > max.Y) { tempData = min.Y; min.Y = max.Y; max.Y = tempData; }
            if (min.Z > max.Z) { tempData = min.Z; min.Z = max.Z; max.Z = tempData; }
            AABB.Min = min;
            AABB.Max = max;
            return AABB;
        }
#endregion

        #region Draws
        static public void DrawHouse(Matrix view, Matrix projection)
        {
            foreach (Model model in mHouse)
            {
                Matrix[] mTransforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(mTransforms);


                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();

                        effect.World = mTransforms[mesh.ParentBone.Index] * Matrix.Identity;
                        effect.View = view;
                        effect.Projection = projection;
                    }
                    mesh.Draw();
                }
            }
        }

       
        static public void DrawStatues(Matrix view, Matrix projection)
        {
            foreach (Model model in mStatues)
            {
                Matrix[] mTransforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(mTransforms);


                foreach (ModelMesh mesh in model.Meshes)
                {
                    /*Las estatuas tienen un cubo que actua como bounding box,
                    esos no los queremos dibujar*/
                    if (mesh.Name != "CollisionBox")
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.EnableDefaultLighting();

                            effect.World = mTransforms[mesh.ParentBone.Index] * Matrix.Identity;
                            effect.View = view;
                            effect.Projection = projection;
                        }
                        mesh.Draw();
                    }
                }
            }
        }
        static public void Draw(string objectToDraw, Matrix world, Matrix view, Matrix projection)
        {
            foreach (Model model in mModels)
            {
                if ((string)model.Tag == objectToDraw)
                {
                    Matrix[] mTransforms = new Matrix[model.Bones.Count];
                    model.CopyAbsoluteBoneTransformsTo(mTransforms);

                    
                    foreach (ModelMesh mesh in model.Meshes)
                    {
                        if (mesh.Name != "CollisionBox")
                        {
                            foreach (BasicEffect effect in mesh.Effects)
                            {
                                effect.EnableDefaultLighting();

                                effect.World = mTransforms[mesh.ParentBone.Index] * world;
                                effect.View = view;
                                effect.Projection = projection;
                            }
                            mesh.Draw();
                        }
                    }
                     
                    break;
                }
            }
        }
        #endregion

        #region OtherMethods
        static public Model GetModel(string modelname)
        {
            foreach (Model model in mModels)
            {
                if ((string)model.Tag == modelname)
                {
                    return model;
                }
            }

            return null;
        }
        #endregion
    }
}
